﻿using Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace NextNet
{
    public class NextServer : HandleFile
    {
        //通过订阅事件处理消息
        public delegate void DisposeEventHandle(object sender, DataDisp e);
        public event DisposeEventHandle DisoposeHandle;

        Socket ServerSocket;
        Thread ServerThread;

        List<SocketClient> ListClient = new List<SocketClient>();

        public bool Running
        {
            get
            {
                return (ServerSocket != null || ServerThread != null);
            }
        }

        public bool Start(string ip, int prot)
        {
            if (Running)
            {
                Logfile log = new Logfile(1);
                log.Write("服务端已运行", "Socket");
                return false;
            }
            try
            {
                ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPAddress ipAddress = IPAddress.Parse(ip);
                IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, prot);
                ServerSocket.Bind(ipEndPoint);
                ServerSocket.Listen(100);

                ServerThread = new Thread(ServerListener);
                ServerThread.Start();

                SendHandle += SendMessage;
            }
            catch (Exception ex)
            {
                Logfile log = new Logfile(1);
                log.Write(ex.Message, "Socket");
                return false;
            }

            return true;
        }

        private void SendMessage(SendMessage mess)
        {
            List<byte[]> messageList = null;
            lock (ListClient)
            {
                var client= ListClient.Find((m) => m.ID == mess.ID);
                if (client != null)
                    messageList = client.Message;
            }
            if (messageList != null)
            {
                lock (messageList)
                {
                    messageList.Add(mess.Stream);
                }
            }
        }

        void ServerListener()
        {
            while (true)
            {
                SocketClient terminal = new SocketClient()
                {
                    Client = ServerSocket.Accept(),
                    Message = new List<byte[]>()
                };

                terminal.ID = terminal.GetHashCode();
                EndPoint ipEnd = terminal.Client.RemoteEndPoint;
                string ip = ipEnd.ToString();
                terminal.IP = ip.Substring(0, ip.LastIndexOf(":"));
                terminal.LastTime = DateTime.Now;


                terminal.Sender = new Thread(ClientSender);
                terminal.Sender.Start(terminal);

                terminal.Receiver = new Thread(ClientReceiver);
                terminal.Receiver.Start(terminal);

                lock (ListClient)
                {
                    ListClient.Add(terminal);
                }

                Send(terminal.ID, DataType.Base, MessType.ClientID);
                
            }
        }

        void ClientReceiver(object obj)
        {
            if (obj == null || obj.GetType() != typeof(SocketClient)) return;
            SocketClient terminal = (SocketClient)obj;

            while (true)
            {
                int streamLength = 0;

                byte[] head = new byte[StreamHead.HeadLength];
                byte[] temp = new byte[1024];
                byte[] stream;

                try
                {
                    int sub = StreamHead.HeadLength;
                    int length;

                    while (true)
                    {
                        int len = (temp.Length < sub) ? temp.Length : sub;
                        length = terminal.Client.Receive(temp, len, SocketFlags.None);

                        if (length <= 0) goto End;//重新接收
                        if (length == sub)
                        {
                            Array.Copy(temp, 0, head, head.Length - sub, length);
                            break;
                        }
                        else
                        {
                            Array.Copy(temp, 0, head, head.Length - sub, length);
                            sub -= length;
                        }
                    }
                    StreamHead.Read(head, out streamLength, out int clientID, out DataType dataType, out MessType messType);

                    if (streamLength > 0)
                    {
                        stream = new byte[streamLength];
                        sub = streamLength;
                        while (true)
                        {
                            int len = (temp.Length < sub) ? temp.Length : sub;
                            length = terminal.Client.Receive(temp, len, SocketFlags.None);

                            if (length <= 0) goto End;

                            if (length == sub)
                            {
                                Array.Copy(temp, 0, stream, stream.Length - sub, length);
                                break;
                            }
                            else
                            {
                                Array.Copy(temp, 0, stream, stream.Length - sub, length);
                                sub -= length;
                            }
                        }

                    }
                    else
                    {
                        stream = head;
                    }

                    //处理消息
                    DisoposeHandle?.Invoke(this, new DataDisp()
                    {
                        ID = clientID,
                        Data = dataType,
                        Type = messType,
                        Stream = stream
                    });
                }
                catch
                {
                    goto End;
                }

            }
            End:
            new Thread(ClientRemove).Start(terminal);
        }

        /// <summary>
        /// 向客户端发送消息
        /// </summary>
        /// <param name="obj"></param>
        void ClientSender(object obj)
        {
            if (obj == null || obj.GetType() != typeof(SocketClient)) return;

            SocketClient terminal = (SocketClient)obj;

            while (true)
            {
                byte[] stream = null;

                lock (terminal.Message)
                {
                    if (terminal.Message.Count > 0)
                    {
                        stream = terminal.Message[0];
                        terminal.Message.RemoveAt(0);
                    }
                    if (stream != null)
                    {
                        try
                        {
                            terminal.Client.Send(stream);
                        }
                        catch
                        {
                            goto End;
                        }
                    }
                    else Thread.Sleep(100);
                }

            }
            End:
            new Thread(ClientRemove).Start(terminal);
        }

        /// <summary>
        /// 清理不正常客户端
        /// </summary>
        /// <param name="obj"></param>
        void ClientRemove(object obj)
        {
            if (obj == null || obj.GetType() != typeof(SocketClient)) return;

            SocketClient terminal = (SocketClient)obj;

            lock (ListClient)
            {
                for (int i = 0; i < ListClient.Count; i++)
                {
                    if (ListClient[i] == terminal)
                    {
                        if (ListClient[i].Receiver != null)
                        {
                            ListClient[i].Receiver.Abort();
                            ListClient[i].Receiver = null;
                        }

                        if (ListClient[i].Sender != null)
                        {
                            ListClient[i].Sender.Abort();
                            ListClient[i].Sender = null;
                        }

                        if (ListClient[i].Client != null)
                        {
                            ListClient[i].Client.Close();
                            ListClient[i].Client = null;
                        }

                        ListClient.RemoveAt(i);
                        return;
                    }
                }
            }
        }



    }


}
